package org.acooke.uykfd.mp3

import java.io.File
import java.nio.charset.Charset
import java.sql.Connection

import org.acooke.uykfd.db.Schema

import org.farng.mp3.MP3File

object Walker {

  def walk(action: (File) => Unit, path: File) {
    try {
      for (file <- path.listFiles) {
        if (file.isDirectory) {
          walk(action, file)
        } else if (file.getPath.endsWith(".mp3")) {
          action(file)
        }
      }
    } catch {
      case e: NullPointerException => println("No files at " + path.getPath)
      case e: Exception => println(e)
      case e: AssertionError => println(e)
    }
  }

}

class Importer(cnxn: Connection) {

  /**
   * Remove entries below the given path (which is probaby being rescanned) from
   * the TRACKS table.
   */
  private def preLoad(path: File) = Schema.TRACKS.orm.deletePathBelow(path, cnxn)

  private def postLoad = Schema.TRACKS.orm.clean(cnxn)

  /**
   * Load the file at the given path into the database.
   */
  private def load(prefix: String)(file: File) {
    val mp3 = new MP3File(file)
    val tag = if (mp3.hasID3v2Tag) mp3.getID3v2Tag else mp3.getID3v1Tag
    if (tag == null) {
      println("Failed to parse " + file.getPath)
    } else {
      val fullPath = file.getPath
      val path = if (fullPath.startsWith(prefix)) fullPath.substring(prefix.length)
                 else throw new RuntimeException(fullPath + " not under " + prefix)
      println(path)
      val track = try {Integer.parseInt(tag.getTrackNumberOnAlbum)} catch {case e: Exception => 0}
      val artist = clean(tag.getLeadArtist)
      val album = clean(tag.getAlbumTitle)
      val song = clean(tag.getSongTitle)
      Schema.TRACKS.orm.fromTags(artist, album, song, track, path, cnxn)
    }
  }

  /**
   * There's an confused nightmare of mixed up encodings out there.
   * The MP3 lib is probably already being "smart", but some junk is still getting through.
   * A common error seems to be the values 65533.
   */
  private def clean(tag: String) = tag.filter(c => c != 65533)

  def loadPath(prefix: String, path: File) {
    preLoad(path)
    Walker.walk(load(prefix), path)
    postLoad
  }

}
